package br.ita.battlefarm.pieces;

import java.util.List;
import java.util.Random;

import android.graphics.Color;
import br.ita.battlefarm.core.Orientation;
import br.ita.battlefarm.core.Position;

public abstract class Piece implements Cloneable {

	protected Position _base = new Position(0,0);
	private Position upperPaint;
	private Position lowerPaint;
	private int _color;
	protected Integer image = null;
	
	public void setColor(int color){
		_color = color;
	}
	
	public int getColor(){
		return _color;
	}

	protected abstract void fillPositionsFromBaseFacingUp();

	//Stores every square occupied by the piece (constructed from the base position and orientation)
	protected List<Position> _positions;
	protected Orientation _orientation;

	public Position getBasePosition() {
		return _base;
	}
	
	public Piece(){
		initParams();
	}
	
	public Piece(Position basePosition){
		_base = basePosition;
		initParams();
	}
	
	public void initParams(){
		_orientation = new Orientation();
		Random random = new Random();
		_color = Color.rgb(150+random.nextInt(106), 150+random.nextInt(106), 150+random.nextInt(106));
		fillPositionsFromBaseAndOrientation();
		calculatePaintPositions();		
	}
	
	private void calculatePaintPositions() {
		upperPaint = new Position(_base.x,_base.y);
		lowerPaint = new Position(_base.x,_base.y);
		for( Position pos : _positions ){
			upperPaint.x = Math.min(upperPaint.x, pos.x);
			upperPaint.y = Math.min(upperPaint.y, pos.y);
			lowerPaint.x = Math.max(lowerPaint.x, pos.x);
			lowerPaint.y = Math.max(lowerPaint.y, pos.y);
		}
	}

	public Orientation getOrientation(){
		return _orientation;
	}
	
	public void setBasePositionAndUpdate(Position position) {
		_base = position;
		fillPositionsFromBaseAndOrientation();
	}

	public void rotateLeft() {
		_orientation.rotateLeft();
		rotateOnlyPositionsLeft();
		rotatePaintLeft();
	}

	private void rotatePaintLeft() {
		Position pole = new Position(0,0);
		upperPaint.rotateLeft(pole);
		lowerPaint.rotateLeft(pole);
		fixPaintPostions();
	}

	private void fixPaintPostions() {
		if( upperPaint.x > lowerPaint.x ){
			int aux = upperPaint.x;
			upperPaint.x = lowerPaint.x;
			lowerPaint.x = aux;
		}
		if( upperPaint.y > lowerPaint.y ){
			int aux = upperPaint.y;
			upperPaint.y = lowerPaint.y;
			lowerPaint.y = aux;
		}
	}

	public void rotateRight() {
		_orientation.rotateRight();
		rotateOnlyPositionsRight();
		rotatePaintRight();
	}

	private void rotatePaintRight() {
		Position pole = new Position(0,0);
		upperPaint.rotateRight(pole);
		lowerPaint.rotateRight(pole);
		fixPaintPostions();
	}

	protected void fillPositionsFromBaseAndOrientation() {
		fillPositionsFromBaseFacingUp();
		switch (_orientation.face) {
		case FaceDown:
			rotateOnlyPositionsLeft();
			rotateOnlyPositionsLeft();
			break;
		case FaceLeft:
			rotateOnlyPositionsLeft();
			break;
			
		case FaceRight:
			rotateOnlyPositionsRight();
			break;
		}
	}

	public List<Position> getPositions() {
		return _positions;
	}

	private void rotateOnlyPositionsRight() {
		for(Position p : _positions){
			p.rotateRight(_base);
		}
	}

	private void rotateOnlyPositionsLeft() {
		for(Position p : _positions){
			p.rotateLeft(_base);
		}
	}

	public void moveToOrigin() {
		setBasePositionAndUpdate(new Position(0,0));
		Position minPoint = new Position(_base.x,_base.y);
		for( Position pos : _positions ){
			minPoint.x = Math.min(minPoint.x, pos.x);
			minPoint.y = Math.min(minPoint.y, pos.y);
		}
		Position new_base = new Position(_base.x-minPoint.x,_base.y-minPoint.y);
		setBasePositionAndUpdate(new_base);
	}

	public boolean isReadyToPaint() {
		if( image == null ){
			return false;
		}
		return isDead();
	}
	
	public boolean isDead(){
		for( Position pos : _positions ){
			if( !pos.isHit() ){
				return false;
			}
		}
		return true;
	}

	public Integer getImage() {
		return image;
	}

	public Position getUpperPaint() {
		return upperPaint;
	}

	public Position getLowerPaint() {
		return lowerPaint;
	}

}